package com.bingoogolapple.qrcode.core;

import ohos.agp.components.AttrSet;
import ohos.agp.components.ComponentContainer;
import ohos.agp.components.DependentLayout;
import ohos.agp.components.DirectionalLayout;
import ohos.agp.utils.Rect;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.media.camera.CameraKit;
import ohos.media.camera.device.Camera;
import ohos.media.camera.device.CameraDeviceCallback;
import ohos.media.image.Image;
import ohos.media.image.PixelMap;

public abstract class QRCodeView extends DependentLayout implements CameraPreview.PreviewCallback {
    private CameraPreview mCameraPreview;
    private Delegate mDelegate;
    protected ScanBoxView mScanBoxView;
    protected CameraKit mCamera;
    protected boolean mSpotAble = false;
    private long mLastPreviewFrameTime = 0;
    private int mCameraId = 0;
    protected BarcodeType mBarcodeType = BarcodeType.HIGH_FREQUENCY;
    private CameraDeviceCallback cameraDeviceCallback;
    private EventHandler onImageArrivalHandler;

    public QRCodeView(Context context) {
        this(context, null);
    }

    public QRCodeView(Context context, AttrSet attrSet) {
        this(context, attrSet, "");
    }

    public QRCodeView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        initView(context, attrSet);
    }


    public void initView(Context context, AttrSet attrSet) {
        LogUtil.info("initView...");
        LogUtil.error("Qrcodeview....initView...");
        mScanBoxView = new ScanBoxView(context);
        mScanBoxView.init(this, attrSet,context);

        onImageArrivalHandler = new EventHandler(EventRunner.create("onImageArrival"));
        mCameraPreview = new CameraPreview(context, this);
        mCameraPreview.setPreviewCallback(this);
        DirectionalLayout.LayoutConfig params = new DirectionalLayout.LayoutConfig(
                ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT);
        mCameraPreview.setLayoutConfig(params);
        addComponent(mCameraPreview);

        DirectionalLayout.LayoutConfig boxParams = new DirectionalLayout.LayoutConfig(
                ComponentContainer.LayoutConfig.MATCH_PARENT, ComponentContainer.LayoutConfig.MATCH_PARENT);
        addComponent(mScanBoxView, boxParams);
    }

    public void removeCameraPreView() {
        if (mCameraPreview != null) {
            removeComponent(mCameraPreview);
            invalidate();
        }
    }

    protected abstract void setupReader();



    /**
     * 设置扫描二维码的代理
     *
     * @param delegate 扫描二维码的代理
     */
    public void setDelegate(Delegate delegate) {
        mDelegate = delegate;
    }


    public ScanBoxView getScanBoxView() {
        return mScanBoxView;
    }

    /**
     * 显示扫描框
     */
    public void showScanRect() {
        if (mScanBoxView != null) {
            mScanBoxView.setVisibility(VISIBLE);
        }
    }

    /**
     * 停止扫描返回
     */
    public void stopCallBack() {
        if (mDelegate != null) {
            mDelegate = null;
        }
    }


    /**
     * 隐藏扫描框
     */
    public void hiddenScanRect() {
        if (mScanBoxView != null) {
            mScanBoxView.setVisibility(INVISIBLE);
        }
    }

    /**
     * 打开后置摄像头开始预览，但是并未开始识别
     */
    public void startCamera() {

        LogUtil.error("startCamera...");
        mSpotAble = true;

        if (mCameraPreview != null) {
            mCameraPreview.initView(this);
        }

    }


    private int findCameraIdByFacing(int cameraFacing) {
        return 0;
    }


    /**
     * 关闭摄像头预览，并且隐藏扫描框
     */
    public void stopCamera() {
        try {
            mSpotAble = false;
            stopSpotAndHiddenRect();
            if (mCameraPreview != null) {
                mCameraPreview.stopCameraPreview();
            }
        } catch (Exception e) {
            LogUtil.error(e.getMessage());
        }
    }



    /**
     * 开始识别
     */
    public void startSpot() {
        if (mSpotAble) {

            return;
        }
        mSpotAble = true;
        startCamera();

    }

    /**
     * 停止识别
     */
    public void stopSpot() {
        mSpotAble = false;


    }

    /**
     * 停止识别，并且隐藏扫描框
     */
    public void stopSpotAndHiddenRect() {
        stopSpot();
        hiddenScanRect();
    }

    /**
     * 显示扫描框，并开始识别
     */
    public void startSpotAndShowRect() {
        startSpot();
        showScanRect();
    }


    /**
     * 打开闪光灯
     */
    public void openFlashlight() {
        mCameraPreview.openFlashlight();
    }

    /**
     * 关闭闪光灯
     */
    public void closeFlashlight() {
        mCameraPreview.closeFlashlight();
    }

    /**
     * 销毁二维码扫描控件
     */
    public void onDestroy() {
        stopCamera();

    }

    /**
     * 切换成扫描条码样式
     */
    public void changeToScanBarcodeStyle() {
        if (!mScanBoxView.getIsBarcode()) {
            mScanBoxView.setIsBarcode(true);
        }
    }

    /**
     * 切换成扫描二维码样式
     */
    public void changeToScanQRCodeStyle() {
        if (mScanBoxView.getIsBarcode()) {
            mScanBoxView.setIsBarcode(false);
        }
    }

    /*
     * 当前是否为条码扫描样式
     */
    public boolean getIsScanBarcodeStyle() {
        return mScanBoxView.getIsBarcode();
    }

    private void handleAmbientBrightness(byte[] data, Camera camera) {
    }

    /**
     * 解析本地图片二维码。返回二维码图片里的内容 或 null
     *
     * @param picturePath 要解析的二维码图片本地路径
     */
    public void decodeQRCode(String picturePath) {

    }

    /**
     * 解析 Bitmap 二维码。返回二维码图片里的内容 或 null
     *
     * @param bitmap 要解析的二维码图片
     */
    public void decodeQRCode(PixelMap bitmap) {

    }

    protected abstract ScanResult processData(byte[] data, int width, int height, boolean isRetry);


    protected abstract ScanResult processBitmapData(PixelMap bitmap);

    void onPostParseData(ScanResult scanResult) {
    }

    void onPostParseBitmapOrPicture(ScanResult scanResult) {
    }

    void onScanBoxRectChanged(Rect rect) {
        mCameraPreview.onScanBoxRectChanged(rect);
    }

    /*
     * 是否显示定位点
     */
    protected boolean isShowLocationPoint() {
        return mScanBoxView != null && mScanBoxView.isShowLocationPoint();
    }

    /*
     * 是否自动缩放
     */
    protected boolean isAutoZoom() {
        return mScanBoxView != null && mScanBoxView.isAutoZoom();
    }

    protected boolean transformToViewCoordinates(final PointF[] pointArr, final Rect scanBoxAreaRect, final boolean isNeedAutoZoom, final String result) {
        return false;
    }

    private boolean handleAutoZoom(float[] locationPoints, final String result) {
        return false;
    }

    private void startAutoZoom(int oldZoom, int newZoom, final String result) {

    }

    private float transform(float originX, float originY, float cameraPreviewWidth, float cameraPreviewHeight, boolean isMirrorPreview, int statusBarHeight) {
        return 0;
    }




    private void parseImageData(Image image) {
        try {
            PixelMap pixelMap = CanvasUtil.image2Pixel(image);
            LogUtil.error("转换pixelmap成功");
            if (image == null) {
                return;
            }
            ScanResult result = processBitmapData(pixelMap);
            if (mDelegate != null && result != null && result.result != null) {
                mDelegate.onScanQRCodeSuccess(result.result);
            }
            pixelMap.release();
            image.release();
        } catch (Exception exception) {
            LogUtil.error("解析返回数据失败");
        }

    }

    @Override
    public void onPreviewFrame(Image image) {
        LogUtil.error("imageReceiver...");

        onImageArrivalHandler.postTask(() -> {
            LogUtil.error("onImageArrival runner");
            parseImageData(image);
        });

    }



    public interface Delegate {
        /**
         * 处理扫描结果
         *
         * @param result 摄像头扫码时只要回调了该方法 result 就一定有值，不会为 null。解析本地图片或 Bitmap 时 result 可能为 null
         */
        void onScanQRCodeSuccess(String result);

        /**
         * 摄像头环境亮度发生变化
         *
         * @param isDark 是否变暗
         */
        void onCameraAmbientBrightnessChanged(boolean isDark);

        /**
         * 处理打开相机出错
         */
        void onScanQRCodeOpenCameraError();
    }

}
